﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Net.Sockets;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using IPC.Communication.Core;
using IPC.Communication.Core.IMessage;
using IPC.Communication.Core.Net;
using IPC.Communication.Reflection;

namespace IPC.Communication.Profinet.Omron
{
    public class OmronFinsNet : NetworkDeviceBase
{
	private readonly byte[] handSingle = new byte[20]
	{
		70,
		73,
		78,
		83,
		0,
		0,
		0,
		12,
		0,
		0,
		0,
		0,
		0,
		0,
		0,
		0,
		0,
		0,
		0,
		0
	};

	[HslMqttApi(HttpMethod = "GET", Description = "Get or set the IP address of the remote server. If it is a local test, then it needs to be set to 127.0.0.1")]
	public override string IpAddress
	{
		get
		{
			return base.IpAddress;
		}
		set
		{
			base.IpAddress = value;
			DA1 = Convert.ToByte(base.IpAddress.Substring(base.IpAddress.LastIndexOf(".") + 1));
		}
	}

        private byte _icf = 128;
        private byte _rsv = 0;
        private byte _gct = 2;
        private byte _dna = 0;
        private byte _da1 = 19;
        private byte _da2 = 0;
        private byte _sna = 0;
        private byte _sa1 = 1;
        private byte _sid = 0;
        private int _readSplits = 500;
	public byte ICF
	{
		get { return _icf; }
		set { _icf = value; }
	}


	public byte RSV
	{
		get { return _rsv; }
		private set { _rsv = value; }
	}


	public byte GCT
	{
		get { return _gct; }
		set { _gct = value; }
	}


	public byte DNA
	{
		get { return _dna; }
		set { _dna = value; }
	}


	[HslMqttApi(HttpMethod = "GET", Description = "PLC node address. This value is assigned by default after the IP address is configured. The default is the last bit of the IP address.")]
	public byte DA1
	{
		get { return _da1; }
		set { _da1 = value; }
	}


	public byte DA2
	{
		get { return _da2; }
		set { _da2 = value; }
	}


	public byte SNA
	{
		get { return _sna; }
		set { _sna = value; }
	}


	[HslMqttApi(HttpMethod = "GET", Description = "The node address of the host computer is 0x01 by default. After connecting to the PLC, the PLC will set the current value.")]
	public byte SA1
	{
		get { return _sa1; }
		set { _sa1 = value; }
	}


	public byte SA2
	{
		get;
		set;
	}

	public byte SID
	{
		get { return _sid; }
		set { _sid = value; }
	}


	public int ReadSplits
	{
        get { return _readSplits; }
        set { _readSplits = value; }
	}


	public OmronFinsNet()
	{
		base.WordLength = 1;
		base.ByteTransform = new ReverseWordTransform();
		base.ByteTransform.DataFormat = DataFormat.CDAB;
		base.ByteTransform.IsStringReverseByteWord = true;
	}

	public OmronFinsNet(string ipAddress, int port)
		: this()
	{
		IpAddress = ipAddress;
		Port = port;
	}

	protected override INetMessage GetNewNetMessage()
	{
		return new FinsMessage();
	}

	private byte[] PackCommand(byte[] cmd)
	{
		byte[] array = new byte[26 + cmd.Length];
		Array.Copy(handSingle, 0, array, 0, 4);
		byte[] bytes = BitConverter.GetBytes(array.Length - 8);
		Array.Reverse(bytes);
		bytes.CopyTo(array, 4);
		array[11] = 2;
		array[16] = ICF;
		array[17] = RSV;
		array[18] = GCT;
		array[19] = DNA;
		array[20] = DA1;
		array[21] = DA2;
		array[22] = SNA;
		array[23] = SA1;
		array[24] = SA2;
		array[25] = SID;
		cmd.CopyTo(array, 26);
		return array;
	}

	protected override OperateResult InitializationOnConnect(Socket socket)
	{
		OperateResult<byte[]> operateResult = ReadFromCoreServer(socket, handSingle, hasResponseData: true, usePackAndUnpack: false);
		if (!operateResult.IsSuccess)
		{
			return operateResult;
		}
		int num = BitConverter.ToInt32(new byte[4]
		{
			operateResult.Content[15],
			operateResult.Content[14],
			operateResult.Content[13],
			operateResult.Content[12]
		}, 0);
		if (num != 0)
		{
			return new OperateResult(num, OmronFinsNetHelper.GetStatusDescription(num));
		}
		if (operateResult.Content.Length >= 20)
		{
			SA1 = operateResult.Content[19];
		}
		if (operateResult.Content.Length >= 24)
		{
			DA1 = operateResult.Content[23];
		}
		return OperateResult.CreateSuccessResult();
	}

    //[AsyncStateMachine(typeof(<InitializationOnConnectAsync>d__52))]
    //[DebuggerStepThrough]
    //protected override Task<OperateResult> InitializationOnConnectAsync(Socket socket)
    //{
    //    <InitializationOnConnectAsync>d__52 stateMachine = new <InitializationOnConnectAsync>d__52();
    //    stateMachine.<>t__builder = AsyncTaskMethodBuilder<OperateResult>.Create();
    //    stateMachine.<>4__this = this;
    //    stateMachine.socket = socket;
    //    stateMachine.<>1__state = -1;
    //    stateMachine.<>t__builder.Start(ref stateMachine);
    //    return stateMachine.<>t__builder.Task;
    //}

	protected override byte[] PackCommandWithHeader(byte[] command)
	{
		return PackCommand(command);
	}

	protected override OperateResult<byte[]> UnpackResponseContent(byte[] send, byte[] response)
	{
		return OmronFinsNetHelper.ResponseValidAnalysis(response);
	}

	[HslMqttApi("ReadByteArray", "")]
	public override OperateResult<byte[]> Read(string address, ushort length)
	{
		return OmronFinsNetHelper.Read(this, address, length, ReadSplits);
	}

	[HslMqttApi("WriteByteArray", "")]
	public override OperateResult Write(string address, byte[] value)
	{
		return OmronFinsNetHelper.Write(this, address, value);
	}

	[HslMqttApi("ReadString", "")]
	public override OperateResult<string> ReadString(string address, ushort length)
	{
		return base.ReadString(address, length, Encoding.UTF8);
	}

	[HslMqttApi("WriteString", "")]
	public override OperateResult Write(string address, string value)
	{
		return base.Write(address, value, Encoding.UTF8);
	}

    //[AsyncStateMachine(typeof(<ReadAsync>d__59))]
    //[DebuggerStepThrough]
    //public override Task<OperateResult<byte[]>> ReadAsync(string address, ushort length)
    //{
    //    <ReadAsync>d__59 stateMachine = new <ReadAsync>d__59();
    //    stateMachine.<>t__builder = AsyncTaskMethodBuilder<OperateResult<byte[]>>.Create();
    //    stateMachine.<>4__this = this;
    //    stateMachine.address = address;
    //    stateMachine.length = length;
    //    stateMachine.<>1__state = -1;
    //    stateMachine.<>t__builder.Start(ref stateMachine);
    //    return stateMachine.<>t__builder.Task;
    //}

    //[AsyncStateMachine(typeof(<WriteAsync>d__60))]
    //[DebuggerStepThrough]
    //public override Task<OperateResult> WriteAsync(string address, byte[] value)
    //{
    //    <WriteAsync>d__60 stateMachine = new <WriteAsync>d__60();
    //    stateMachine.<>t__builder = AsyncTaskMethodBuilder<OperateResult>.Create();
    //    stateMachine.<>4__this = this;
    //    stateMachine.address = address;
    //    stateMachine.value = value;
    //    stateMachine.<>1__state = -1;
    //    stateMachine.<>t__builder.Start(ref stateMachine);
    //    return stateMachine.<>t__builder.Task;
    //}

    //[AsyncStateMachine(typeof(<ReadStringAsync>d__61))]
    //[DebuggerStepThrough]
    //public override Task<OperateResult<string>> ReadStringAsync(string address, ushort length)
    //{
    //    <ReadStringAsync>d__61 stateMachine = new <ReadStringAsync>d__61();
    //    stateMachine.<>t__builder = AsyncTaskMethodBuilder<OperateResult<string>>.Create();
    //    stateMachine.<>4__this = this;
    //    stateMachine.address = address;
    //    stateMachine.length = length;
    //    stateMachine.<>1__state = -1;
    //    stateMachine.<>t__builder.Start(ref stateMachine);
    //    return stateMachine.<>t__builder.Task;
    //}

    //[AsyncStateMachine(typeof(<WriteAsync>d__62))]
    //[DebuggerStepThrough]
    //public override Task<OperateResult> WriteAsync(string address, string value)
    //{
    //    <WriteAsync>d__62 stateMachine = new <WriteAsync>d__62();
    //    stateMachine.<>t__builder = AsyncTaskMethodBuilder<OperateResult>.Create();
    //    stateMachine.<>4__this = this;
    //    stateMachine.address = address;
    //    stateMachine.value = value;
    //    stateMachine.<>1__state = -1;
    //    stateMachine.<>t__builder.Start(ref stateMachine);
    //    return stateMachine.<>t__builder.Task;
    //}

	[HslMqttApi("ReadBoolArray", "")]
	public override OperateResult<bool[]> ReadBool(string address, ushort length)
	{
		return OmronFinsNetHelper.ReadBool(this, address, length, ReadSplits);
	}

	[HslMqttApi("WriteBoolArray", "")]
	public override OperateResult Write(string address, bool[] values)
	{
		return OmronFinsNetHelper.Write(this, address, values);
	}

    //[AsyncStateMachine(typeof(<ReadBoolAsync>d__65))]
    //[DebuggerStepThrough]
    //public override Task<OperateResult<bool[]>> ReadBoolAsync(string address, ushort length)
    //{
    //    <ReadBoolAsync>d__65 stateMachine = new <ReadBoolAsync>d__65();
    //    stateMachine.<>t__builder = AsyncTaskMethodBuilder<OperateResult<bool[]>>.Create();
    //    stateMachine.<>4__this = this;
    //    stateMachine.address = address;
    //    stateMachine.length = length;
    //    stateMachine.<>1__state = -1;
    //    stateMachine.<>t__builder.Start(ref stateMachine);
    //    return stateMachine.<>t__builder.Task;
    //}

    //[AsyncStateMachine(typeof(<WriteAsync>d__66))]
    //[DebuggerStepThrough]
    //public override Task<OperateResult> WriteAsync(string address, bool[] values)
    //{
    //    <WriteAsync>d__66 stateMachine = new <WriteAsync>d__66();
    //    stateMachine.<>t__builder = AsyncTaskMethodBuilder<OperateResult>.Create();
    //    stateMachine.<>4__this = this;
    //    stateMachine.address = address;
    //    stateMachine.values = values;
    //    stateMachine.<>1__state = -1;
    //    stateMachine.<>t__builder.Start(ref stateMachine);
    //    return stateMachine.<>t__builder.Task;
    //}

	[HslMqttApi(ApiTopic = "Run", Description = "将CPU单元的操作模式更改为RUN，从而使PLC能够执行其程序。")]
	public OperateResult Run()
	{
		return OmronFinsNetHelper.Run(this);
	}

	[HslMqttApi(ApiTopic = "Stop", Description = "将CPU单元的操作模式更改为PROGRAM，停止程序执行。")]
	public OperateResult Stop()
	{
		return OmronFinsNetHelper.Stop(this);
	}

	[HslMqttApi(ApiTopic = "ReadCpuUnitData", Description = "读取CPU的一些数据信息，主要包含型号，版本，一些数据块的大小。")]
	public OperateResult<OmronCpuUnitData> ReadCpuUnitData()
	{
		return OmronFinsNetHelper.ReadCpuUnitData(this);
	}

	[HslMqttApi(ApiTopic = "ReadCpuUnitStatus", Description = "读取CPU单元的一些操作状态数据，主要包含运行状态，工作模式，错误信息等。")]
	public OperateResult<OmronCpuUnitStatus> ReadCpuUnitStatus()
	{
		return OmronFinsNetHelper.ReadCpuUnitStatus(this);
	}

    //[AsyncStateMachine(typeof(<RunAsync>d__71))]
    //[DebuggerStepThrough]
    //public Task<OperateResult> RunAsync()
    //{
    //    <RunAsync>d__71 stateMachine = new <RunAsync>d__71();
    //    stateMachine.<>t__builder = AsyncTaskMethodBuilder<OperateResult>.Create();
    //    stateMachine.<>4__this = this;
    //    stateMachine.<>1__state = -1;
    //    stateMachine.<>t__builder.Start(ref stateMachine);
    //    return stateMachine.<>t__builder.Task;
    //}

    //[AsyncStateMachine(typeof(<StopAsync>d__72))]
    //[DebuggerStepThrough]
    //public Task<OperateResult> StopAsync()
    //{
    //    <StopAsync>d__72 stateMachine = new <StopAsync>d__72();
    //    stateMachine.<>t__builder = AsyncTaskMethodBuilder<OperateResult>.Create();
    //    stateMachine.<>4__this = this;
    //    stateMachine.<>1__state = -1;
    //    stateMachine.<>t__builder.Start(ref stateMachine);
    //    return stateMachine.<>t__builder.Task;
    //}

    //[AsyncStateMachine(typeof(<ReadCpuUnitDataAsync>d__73))]
    //[DebuggerStepThrough]
    //public Task<OperateResult<OmronCpuUnitData>> ReadCpuUnitDataAsync()
    //{
    //    <ReadCpuUnitDataAsync>d__73 stateMachine = new <ReadCpuUnitDataAsync>d__73();
    //    stateMachine.<>t__builder = AsyncTaskMethodBuilder<OperateResult<OmronCpuUnitData>>.Create();
    //    stateMachine.<>4__this = this;
    //    stateMachine.<>1__state = -1;
    //    stateMachine.<>t__builder.Start(ref stateMachine);
    //    return stateMachine.<>t__builder.Task;
    //}

    //[AsyncStateMachine(typeof(<ReadCpuUnitStatusAsync>d__74))]
    //[DebuggerStepThrough]
    //public Task<OperateResult<OmronCpuUnitStatus>> ReadCpuUnitStatusAsync()
    //{
    //    <ReadCpuUnitStatusAsync>d__74 stateMachine = new <ReadCpuUnitStatusAsync>d__74();
    //    stateMachine.<>t__builder = AsyncTaskMethodBuilder<OperateResult<OmronCpuUnitStatus>>.Create();
    //    stateMachine.<>4__this = this;
    //    stateMachine.<>1__state = -1;
    //    stateMachine.<>t__builder.Start(ref stateMachine);
    //    return stateMachine.<>t__builder.Task;
    //}

	public override string ToString()
	{
		return String.Format("OmronFinsNet[{0}:{1}]", IpAddress, Port);
	}
}
}
